/**
 * 内存扫描模块
 * 用于从进程内存中查找和提取数据
 */

const os = require('os');
const fs = require('fs');
const path = require('path');
const { exec, execFile } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
const execFileAsync = promisify(execFile);

// 常见的数据模式
const DATA_PATTERNS = {
  // Cookie相关模式
  COOKIE: /(?:cookie|login|auth|token|session)s?[=:]["']?([^"';,}\s]+)/i,
  // URL模式
  URL: /https?:\/\/[a-z0-9][-a-z0-9]*(\.[a-z0-9][-a-z0-9]*)+[^\s'"<>]*/i,
  // JSON模式
  JSON: /{[\s\S]*?}/,
  // 键值对模式
  KEY_VALUE: /["']?[\w-]+["']?\s*[=:]\s*["']?[^"';,}\s]+["']?/i,
};

/**
 * 从进程内存中扫描并提取数据
 * @param {number} pid - 进程ID
 * @param {Object} options - 扫描选项
 * @returns {Promise<Object>} - 扫描结果
 */
async function scanProcessMemory(pid, options = {}) {
  if (!pid) {
    throw new Error('缺少进程ID');
  }
  
  const platform = os.platform();
  
  try {
    if (platform === 'win32') {
      return await scanWindowsProcessMemory(pid, options);
    } else if (platform === 'darwin') {
      return await scanMacOSProcessMemory(pid, options);
    } else {
      return await scanLinuxProcessMemory(pid, options);
    }
  } catch (err) {
    console.error(`内存扫描出错: ${err.message}`);
    return { pid, data: [], error: err.message };
  }
}

/**
 * 扫描Windows进程内存
 * @param {number} pid - 进程ID
 * @param {Object} options - 扫描选项
 * @returns {Promise<Object>} - 扫描结果
 */
async function scanWindowsProcessMemory(pid, options = {}) {
  try {
    // 获取进程信息
    const { stdout: procInfo } = await execAsync(`wmic process where ProcessId=${pid} get CommandLine,ExecutablePath`);
    const exePath = procInfo.trim().split('\n')[1]?.trim() || '';
    
    // 检查进程类型
    const isElectron = exePath.includes('electron') || exePath.includes('node');
    const isDotNet = exePath.toLowerCase().includes('.net') || exePath.toLowerCase().endsWith('.exe');
    const isCPP = exePath.includes('bin') || (!isElectron && !isDotNet);
    
    // 创建临时文件
    const tempDir = os.tmpdir();
    const dumpFile = path.join(tempDir, `memdump_${pid}_${Date.now()}.dmp`);
    
    // 使用适当的工具进行内存转储
    if (isDotNet) {
      // .NET进程使用ProcDump或其他工具转储
      await execFileAsync('powershell', [
        '-Command',
        `Add-Type -Assembly System.Diagnostics.Process; $process = [System.Diagnostics.Process]::GetProcessById(${pid}); $stream = [System.IO.File]::Create('${dumpFile}'); $process.Dump($stream); $stream.Close()`
      ]);
    } else {
      // 通用进程
      // 注意：这里需要Windows上的转储工具，如ProcDump
      // 以下是简化实现，实际应用需要部署ProcDump或类似工具
      await execFileAsync('powershell', [
        '-Command',
        `Get-Process -Id ${pid} | ForEach-Object { [System.Runtime.InteropServices.Marshal]::ReadInt32($_.Handle) } | Out-File '${dumpFile}'`
      ]);
    }
    
    // 从转储文件中提取数据
    const extractedData = await extractDataFromDumpFile(dumpFile, options);
    
    // 清理临时文件
    try {
      fs.unlinkSync(dumpFile);
    } catch (e) {
      // 忽略清理错误
    }
    
    return {
      pid,
      processType: isDotNet ? '.NET' : (isElectron ? 'Electron' : (isCPP ? 'C++' : 'Unknown')),
      data: extractedData
    };
  } catch (err) {
    console.error(`Windows内存扫描出错: ${err.message}`);
    return { pid, data: [], error: err.message };
  }
}

/**
 * 扫描macOS进程内存
 * @param {number} pid - 进程ID
 * @param {Object} options - 扫描选项
 * @returns {Promise<Object>} - 扫描结果
 */
async function scanMacOSProcessMemory(pid, options = {}) {
  try {
    // 检查进程类型
    const { stdout: procInfo } = await execAsync(`ps -p ${pid} -o command`);
    const cmdLine = procInfo.trim().split('\n')[1] || '';
    
    const isElectron = cmdLine.includes('electron') || cmdLine.includes('node');
    const isNative = cmdLine.includes('.app/Contents/MacOS/');
    const isCPP = !isElectron && !isNative;
    
    // 创建临时文件
    const tempDir = os.tmpdir();
    const dumpFile = path.join(tempDir, `memdump_${pid}_${Date.now()}.bin`);
    
    // macOS需要使用lldb或gcore等工具进行内存转储
    // 以下是简化实现，实际应用需要提升权限并使用适当的工具
    await execAsync(`sudo dtrace -p ${pid} -o ${dumpFile} -n 'BEGIN { exit(0); }'`);
    
    // 或者尝试使用lldb
    /*
    await execFileAsync('bash', [
      '-c',
      `echo "process attach --pid ${pid}\\ndump memory ${dumpFile} 0x0 0x7fffffffffff\\ndetach\\nquit" | lldb`
    ]);
    */
    
    // 从转储文件中提取数据
    const extractedData = await extractDataFromDumpFile(dumpFile, options);
    
    // 清理临时文件
    try {
      fs.unlinkSync(dumpFile);
    } catch (e) {
      // 忽略清理错误
    }
    
    return {
      pid,
      processType: isElectron ? 'Electron' : (isNative ? 'macOS Native' : (isCPP ? 'C++' : 'Unknown')),
      data: extractedData
    };
  } catch (err) {
    console.error(`macOS内存扫描出错: ${err.message}`);
    return { pid, data: [], error: err.message };
  }
}

/**
 * 扫描Linux进程内存
 * @param {number} pid - 进程ID
 * @param {Object} options - 扫描选项
 * @returns {Promise<Object>} - 扫描结果
 */
async function scanLinuxProcessMemory(pid, options = {}) {
  try {
    // 检查进程类型
    const { stdout: procInfo } = await execAsync(`ps -p ${pid} -o cmd`);
    const cmdLine = procInfo.trim().split('\n')[1] || '';
    
    const isElectron = cmdLine.includes('electron') || cmdLine.includes('node');
    const isQt = cmdLine.includes('Qt') || cmdLine.includes('qt');
    const isCPP = !isElectron && !isQt;
    
    // 创建临时文件
    const tempDir = os.tmpdir();
    const dumpFile = path.join(tempDir, `memdump_${pid}_${Date.now()}.bin`);
    
    // 使用gcore转储内存 (需要gdb)
    await execAsync(`gcore -o ${dumpFile} ${pid}`);
    
    // 从转储文件中提取数据
    const extractedData = await extractDataFromDumpFile(dumpFile, options);
    
    // 清理临时文件
    try {
      fs.unlinkSync(dumpFile);
      // 清理gcore生成的文件
      fs.unlinkSync(`${dumpFile}.${pid}`);
    } catch (e) {
      // 忽略清理错误
    }
    
    return {
      pid,
      processType: isElectron ? 'Electron' : (isQt ? 'Qt' : (isCPP ? 'C++' : 'Unknown')),
      data: extractedData
    };
  } catch (err) {
    console.error(`Linux内存扫描出错: ${err.message}`);
    return { pid, data: [], error: err.message };
  }
}

/**
 * 从转储文件中提取数据
 * @param {string} dumpFile - 转储文件路径
 * @param {Object} options - 提取选项
 * @returns {Promise<Array>} - 提取的数据
 */
async function extractDataFromDumpFile(dumpFile, options = {}) {
  try {
    // 读取转储文件
    const buffer = await fs.promises.readFile(dumpFile);
    
    // 将二进制数据转换为字符串
    // 注意：这是简化实现，实际应用需要更复杂的内存解析逻辑
    let textContent = '';
    for (let i = 0; i < buffer.length; i++) {
      // 只处理ASCII可打印字符
      if (buffer[i] >= 32 && buffer[i] <= 126) {
        textContent += String.fromCharCode(buffer[i]);
      } else if ([10, 13, 9].includes(buffer[i])) {
        // 保留换行符和制表符
        textContent += String.fromCharCode(buffer[i]);
      } else {
        // 非ASCII字符替换为空格
        textContent += ' ';
      }
    }
    
    // 提取有意义的数据
    const extractedData = [];
    
    // 根据选项决定提取哪些类型的数据
    const { extractCookies = true, extractUrls = true, extractJson = true } = options;
    
    // 提取Cookie
    if (extractCookies) {
      const cookieMatches = extractPatternMatches(textContent, DATA_PATTERNS.COOKIE);
      extractedData.push(...cookieMatches.map(match => ({
        type: 'COOKIE',
        value: match
      })));
      
      // 提取键值对形式的数据
      const keyValueMatches = extractPatternMatches(textContent, DATA_PATTERNS.KEY_VALUE);
      const filteredKeyValues = keyValueMatches.filter(kv => {
        const lowerKv = kv.toLowerCase();
        return lowerKv.includes('cookie') || 
               lowerKv.includes('token') || 
               lowerKv.includes('auth') || 
               lowerKv.includes('session') ||
               lowerKv.includes('login');
      });
      
      extractedData.push(...filteredKeyValues.map(match => ({
        type: 'KEY_VALUE',
        value: match
      })));
    }
    
    // 提取URL
    if (extractUrls) {
      const urlMatches = extractPatternMatches(textContent, DATA_PATTERNS.URL);
      extractedData.push(...urlMatches.map(match => ({
        type: 'URL',
        value: match
      })));
    }
    
    // 提取JSON
    if (extractJson) {
      const jsonMatches = extractJSONObjects(textContent);
      extractedData.push(...jsonMatches.map(match => ({
        type: 'JSON',
        value: match
      })));
    }
    
    // 去重
    const uniqueData = [];
    const seenValues = new Set();
    
    for (const item of extractedData) {
      if (!seenValues.has(item.value)) {
        seenValues.add(item.value);
        uniqueData.push(item);
      }
    }
    
    return uniqueData;
  } catch (err) {
    console.error(`提取数据出错: ${err.message}`);
    return [];
  }
}

/**
 * 从文本中提取符合模式的匹配项
 * @param {string} text - 文本内容
 * @param {RegExp} pattern - 正则表达式模式
 * @returns {Array<string>} - 匹配结果数组
 */
function extractPatternMatches(text, pattern) {
  const matches = [];
  let match;
  const regex = new RegExp(pattern, 'g');
  
  while ((match = regex.exec(text)) !== null) {
    // 使用第一个捕获组（如果有）或完整匹配
    const value = match[1] || match[0];
    
    // 检查值的有效性
    if (value && value.length >= 3 && value.length <= 2000) {
      matches.push(value);
    }
    
    // 避免无限循环
    if (regex.lastIndex === match.index) {
      regex.lastIndex++;
    }
  }
  
  return matches;
}

/**
 * 从文本中提取JSON对象
 * @param {string} text - 文本内容
 * @returns {Array<string>} - JSON字符串数组
 */
function extractJSONObjects(text) {
  const results = [];
  
  // 查找所有可能的JSON对象起始位置
  for (let i = 0; i < text.length; i++) {
    if (text[i] === '{') {
      try {
        // 尝试提取完整的JSON对象
        let depth = 1;
        let end = i + 1;
        
        while (end < text.length && depth > 0) {
          if (text[end] === '{') depth++;
          else if (text[end] === '}') depth--;
          end++;
        }
        
        if (depth === 0) {
          const jsonStr = text.substring(i, end);
          
          // 尝试解析JSON以验证有效性
          try {
            const parsed = JSON.parse(jsonStr);
            
            // 检查是否包含有意义的数据
            const jsonString = JSON.stringify(parsed);
            if (jsonString.length >= 10 && jsonString.length <= 5000) {
              // 检查是否包含cookie或认证相关数据
              if (jsonString.toLowerCase().includes('cookie') || 
                  jsonString.toLowerCase().includes('token') || 
                  jsonString.toLowerCase().includes('auth') || 
                  jsonString.toLowerCase().includes('session') ||
                  jsonString.toLowerCase().includes('login')) {
                results.push(jsonStr);
              }
            }
          } catch (e) {
            // 不是有效的JSON，忽略
          }
        }
      } catch (e) {
        // 忽略提取错误
        continue;
      }
    }
  }
  
  return results;
}

/**
 * 查找进程加载的可执行文件和模块
 * @param {number} pid - 进程ID
 * @returns {Promise<Array>} - 模块信息数组
 */
async function findProcessModules(pid) {
  const platform = os.platform();
  
  try {
    if (platform === 'win32') {
      return await findWindowsProcessModules(pid);
    } else if (platform === 'darwin') {
      return await findMacOSProcessModules(pid);
    } else {
      return await findLinuxProcessModules(pid);
    }
  } catch (err) {
    console.error(`查找进程模块出错: ${err.message}`);
    return [];
  }
}

/**
 * 查找Windows进程加载的模块
 * @param {number} pid - 进程ID
 * @returns {Promise<Array>} - 模块信息数组
 */
async function findWindowsProcessModules(pid) {
  try {
    // 使用PowerShell查询进程模块
    const { stdout } = await execAsync(`powershell -Command "Get-Process -Id ${pid} | Select-Object -ExpandProperty Modules | Select-Object ModuleName, FileName, Size | ConvertTo-Csv -NoTypeInformation"`);
    
    const lines = stdout.trim().split('\n');
    const modules = [];
    
    for (let i = 1; i < lines.length; i++) {
      // 跳过标题行
      const line = lines[i].replace(/^"|"$/g, '');
      const parts = line.split('","');
      
      if (parts.length >= 3) {
        modules.push({
          name: parts[0],
          path: parts[1],
          size: parseInt(parts[2], 10) || 0
        });
      }
    }
    
    return modules;
  } catch (err) {
    console.error(`查找Windows进程模块出错: ${err.message}`);
    return [];
  }
}

/**
 * 查找macOS进程加载的模块
 * @param {number} pid - 进程ID
 * @returns {Promise<Array>} - 模块信息数组
 */
async function findMacOSProcessModules(pid) {
  try {
    // 使用vmmap或者otool查询进程模块
    const { stdout } = await execAsync(`vmmap ${pid}`);
    
    const lines = stdout.trim().split('\n');
    const modules = [];
    const moduleRegex = /^([0-9a-fx]+)\s+-\s+([0-9a-fx]+)\s+\[\s+(\d+)K\]\s+.*\s+(\/.*)/;
    
    for (const line of lines) {
      const match = line.match(moduleRegex);
      if (match) {
        modules.push({
          name: path.basename(match[4]),
          path: match[4],
          size: parseInt(match[3], 10) * 1024 || 0
        });
      }
    }
    
    return modules;
  } catch (err) {
    console.error(`查找macOS进程模块出错: ${err.message}`);
    
    // 尝试备用方法
    try {
      const { stdout } = await execAsync(`lsof -p ${pid} | grep -i '\\.(dylib|so|bundle)$'`);
      
      const lines = stdout.trim().split('\n');
      const modules = [];
      
      for (const line of lines) {
        const parts = line.trim().split(/\s+/);
        if (parts.length >= 9) {
          const path = parts.slice(8).join(' ');
          modules.push({
            name: path.split('/').pop(),
            path: path,
            size: 0 // 无法通过lsof获取大小
          });
        }
      }
      
      return modules;
    } catch (e) {
      return [];
    }
  }
}

/**
 * 查找Linux进程加载的模块
 * @param {number} pid - 进程ID
 * @returns {Promise<Array>} - 模块信息数组
 */
async function findLinuxProcessModules(pid) {
  try {
    // 从/proc/pid/maps读取模块信息
    const { stdout } = await execAsync(`cat /proc/${pid}/maps | grep -i '\\.(so|bin|dll)$'`);
    
    const lines = stdout.trim().split('\n');
    const modules = [];
    const seenPaths = new Set();
    
    for (const line of lines) {
      const parts = line.trim().split(/\s+/);
      if (parts.length >= 6) {
        const path = parts.slice(5).join(' ');
        
        // 避免重复
        if (!seenPaths.has(path) && path.startsWith('/')) {
          seenPaths.add(path);
          
          modules.push({
            name: path.split('/').pop(),
            path: path,
            size: 0 // 需要额外步骤获取大小
          });
        }
      }
    }
    
    return modules;
  } catch (err) {
    console.error(`查找Linux进程模块出错: ${err.message}`);
    return [];
  }
}

/**
 * 提取进程中的字符串
 * @param {number} pid - 进程ID
 * @param {Object} options - 提取选项
 * @returns {Promise<Array<string>>} - 提取的字符串数组
 */
async function extractProcessStrings(pid, options = {}) {
  const platform = os.platform();
  
  try {
    // 创建临时文件
    const tempDir = os.tmpdir();
    const outputFile = path.join(tempDir, `strings_${pid}_${Date.now()}.txt`);
    
    if (platform === 'win32') {
      // Windows需要使用特殊工具如strings.exe或PowerShell
      // 简化实现，使用PowerShell
      await execAsync(`powershell -Command "[System.Diagnostics.Process]::GetProcessById(${pid}).Modules | ForEach-Object { $path = $_.FileName; if (Test-Path $path) { [System.IO.File]::ReadAllBytes($path) | ForEach-Object { if ($_ -ge 32 -and $_ -le 126) { [char]$_ } } } }" > ${outputFile}`);
    } else {
      // Linux和macOS使用strings命令
      try {
        await execAsync(`pgrep -P ${pid} | xargs -I {} strings /proc/{}/mem 2>/dev/null >> ${outputFile}`);
      } catch (e) {
        // 如果上述方法失败，尝试使用内存转储
        try {
          const dumpFile = path.join(tempDir, `memdump_${pid}_${Date.now()}.bin`);
          
          if (platform === 'darwin') {
            await execAsync(`lldb -p ${pid} -o "memory read --outfile ${dumpFile} --force 0x0 0x7fffffffffff" -o exit`);
          } else {
            await execAsync(`gcore -o ${dumpFile} ${pid}`);
          }
          
          await execAsync(`strings ${dumpFile} > ${outputFile}`);
          
          // 清理转储文件
          try { fs.unlinkSync(dumpFile); } catch (e) { /* 忽略 */ }
        } catch (e) {
          // 所有方法都失败
          return [];
        }
      }
    }
    
    // 读取提取的字符串
    const data = await fs.promises.readFile(outputFile, 'utf8');
    const lines = data.split(/\r?\n/).filter(line => line.trim().length >= 3);
    
    // 根据选项过滤字符串
    const { filterPattern, maxResults = 1000 } = options;
    
    let results = lines;
    
    if (filterPattern) {
      const regex = new RegExp(filterPattern, 'i');
      results = results.filter(line => regex.test(line));
    }
    
    // 限制结果数量
    results = results.slice(0, maxResults);
    
    // 清理临时文件
    try {
      fs.unlinkSync(outputFile);
    } catch (e) {
      // 忽略清理错误
    }
    
    return results;
  } catch (err) {
    console.error(`提取进程字符串出错: ${err.message}`);
    return [];
  }
}

/**
 * 分析内存数据中的Cookie信息
 * @param {Array} memoryData - 内存数据数组
 * @returns {Array} - 分析后的Cookie数组
 */
function analyzeCookieData(memoryData) {
  if (!Array.isArray(memoryData)) {
    return [];
  }
  
  const cookies = [];
  
  // 提取键值对类型数据中的Cookie
  const keyValueItems = memoryData.filter(item => item.type === 'KEY_VALUE');
  for (const item of keyValueItems) {
    // 解析键值对
    const match = item.value.match(/["']?([\w-]+)["']?\s*[=:]\s*["']?([^"';,}\s]+)["']?/);
    if (match) {
      const key = match[1];
      const value = match[2];
      
      if (key.toLowerCase().includes('cookie')) {
        // 进一步解析Cookie值
        try {
          const cookieParts = value.split(';');
          for (const part of cookieParts) {
            const cookieMatch = part.trim().match(/([^=]+)=(.+)/);
            if (cookieMatch) {
              cookies.push({
                name: cookieMatch[1].trim(),
                value: cookieMatch[2].trim(),
                domain: '',
                path: '/'
              });
            }
          }
        } catch (e) {
          // 简单添加为单个Cookie
          cookies.push({
            name: key,
            value: value,
            domain: '',
            path: '/'
          });
        }
      }
    }
  }
  
  // 分析JSON类型数据中的Cookie
  const jsonItems = memoryData.filter(item => item.type === 'JSON');
  for (const item of jsonItems) {
    try {
      const json = JSON.parse(item.value);
      
      // 递归扫描JSON对象
      const jsonCookies = scanJsonForCookies(json);
      cookies.push(...jsonCookies);
    } catch (e) {
      // 忽略解析错误
    }
  }
  
  // 去重
  const uniqueCookies = [];
  const seenPairs = new Set();
  
  for (const cookie of cookies) {
    const pair = `${cookie.name}=${cookie.value}`;
    if (!seenPairs.has(pair)) {
      seenPairs.add(pair);
      uniqueCookies.push(cookie);
    }
  }
  
  return uniqueCookies;
}

/**
 * 从JSON对象中扫描Cookie数据
 * @param {Object} json - JSON对象
 * @returns {Array} - 找到的Cookie数组
 */
function scanJsonForCookies(json) {
  const cookies = [];
  
  function scan(obj, parentKey = '') {
    if (!obj || typeof obj !== 'object') return;
    
    if (Array.isArray(obj)) {
      for (let i = 0; i < obj.length; i++) {
        scan(obj[i], `${parentKey}[${i}]`);
      }
      return;
    }
    
    for (const key in obj) {
      const value = obj[key];
      const fullKey = parentKey ? `${parentKey}.${key}` : key;
      
      // 检查是否为Cookie对象
      if (key === 'name' && obj.value !== undefined && typeof obj.name === 'string') {
        cookies.push({
          name: obj.name,
          value: obj.value.toString(),
          domain: obj.domain || '',
          path: obj.path || '/'
        });
        continue;
      }
      
      // 检查键名是否包含Cookie相关词
      if (key.toLowerCase().includes('cookie') && typeof value === 'string') {
        // 尝试解析Cookie字符串
        try {
          const cookieParts = value.split(';');
          for (const part of cookieParts) {
            const match = part.trim().match(/([^=]+)=(.+)/);
            if (match) {
              cookies.push({
                name: match[1].trim(),
                value: match[2].trim(),
                domain: '',
                path: '/'
              });
            }
          }
        } catch (e) {
          // 单个Cookie
          cookies.push({
            name: key,
            value: value,
            domain: '',
            path: '/'
          });
        }
      }
      
      // 递归扫描
      if (typeof value === 'object' && value !== null) {
        scan(value, fullKey);
      }
    }
  }
  
  scan(json);
  return cookies;
}

module.exports = {
  scanProcessMemory,
  findProcessModules,
  extractProcessStrings,
  analyzeCookieData
}; 